package br.pucrio.inf.les.genarch.core.project.navigation.visitors.ast;

/**
 * AST node Visitor use by the ASTExplorer  
 * @author Manoel Marques
 */

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TypeDeclaration;

public class ASTDependenciesVisitor extends ASTVisitor {

	private List<ASTBinding> methodBindings = new ArrayList<ASTBinding>();

	private List<ASTBinding> fieldBindings = new ArrayList<ASTBinding>();

	private List<ASTBinding> classBindings = new ArrayList<ASTBinding>();
	
	private List<ITypeBinding> superInterfaceBindings = new ArrayList<ITypeBinding>();
	
	private ITypeBinding superClassBinding = null;
	
	private boolean typeDeclaration;
	private boolean simpleName;
	private boolean fieldDeclaration;

	public ASTDependenciesVisitor(boolean typeDeclaration, boolean simpleName, boolean fieldDeclaration) {
		this.typeDeclaration = typeDeclaration;
		this.simpleName = simpleName;
		this.fieldDeclaration = fieldDeclaration;
	}

	@Override
	public boolean visit(FieldDeclaration node){
		if(fieldDeclaration){
			
		}
		return fieldDeclaration;
	}

	@Override
	public boolean visit(SimpleName node) {
		if(simpleName){
			IBinding binding= node.resolveBinding();
	
			if (binding instanceof IVariableBinding) {
				if(((IVariableBinding)binding).getVariableDeclaration().getDeclaringClass() != null){
					ASTBinding fieldBinding = new ASTBinding((IVariableBinding)binding, null, node.getStartPosition(), node.getStartPosition() + node.getLength());
					fieldBindings.add(fieldBinding);
				}
			} else if (binding instanceof IMethodBinding) {
				if(((IMethodBinding)binding).getMethodDeclaration().getDeclaringClass() != null){
					ASTBinding methodBinding = new ASTBinding((IMethodBinding)binding, null, node.getStartPosition(), node.getStartPosition() + node.getLength());
					methodBindings.add(methodBinding);
				}
			} else if (binding instanceof ITypeBinding) {
				if(((ITypeBinding)binding) != null){
					ASTBinding classBinding = new ASTBinding((ITypeBinding)binding, null, node.getStartPosition(), node.getStartPosition() + node.getLength());
					classBindings.add(classBinding);
				}
			}
		}
		return simpleName;
	}

	@Override
	public boolean visit(TypeDeclaration node) {
		if(typeDeclaration){
			Name superClassName = node.getSuperclass();
			
			if(superClassName != null){
				ITypeBinding binding = null;
				binding = (ITypeBinding) superClassName.resolveBinding();
				if(binding != null)
					setSuperClassBinding(binding);
			}
			for (Object superInterface : node.superInterfaces()) {
				Name superInterfaceName = (Name) superInterface;
				if (superInterfaceName != null) {
					ITypeBinding binding = null;
					binding = (ITypeBinding) superInterfaceName.resolveBinding();
					if (binding != null)
						superInterfaceBindings.add(binding);
				}
			}
			
		}
		return typeDeclaration;
	}


	public void setMethodBindings(List<ASTBinding> methodBindings) {
		this.methodBindings = methodBindings;
	}

	public List<ASTBinding> getMethodBindings() {
		return methodBindings;
	}

	public void setFieldBindings(List<ASTBinding> fieldBindings) {
		this.fieldBindings = fieldBindings;
	}

	public List<ASTBinding> getFieldBindings() {
		return fieldBindings;
	}

	public void setClassBindings(List<ASTBinding> classBindings) {
		this.classBindings = classBindings;
	}

	public List<ASTBinding> getClassBindings() {
		return classBindings;
	}

	public void setSuperInterfaceBindings(List<ITypeBinding> superInterfaceBindings) {
		this.superInterfaceBindings = superInterfaceBindings;
	}

	public List<ITypeBinding> getSuperInterfaceBindings() {
		return superInterfaceBindings;
	}

	public void setSuperClassBinding(ITypeBinding superClassBinding) {
		this.superClassBinding = superClassBinding;
	}

	public ITypeBinding getSuperClassBinding() {
		return superClassBinding;
	}
}